package com.ruicar.afs.cloud.afscase.loanactivatepool.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruicar.afs.cloud.afscase.approvetask.entity.CaseApproveRecord;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkProcessScheduleInfo;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkTaskPool;
import com.ruicar.afs.cloud.afscase.approvetask.service.CaseApproveRecordService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkProcessScheduleInfoService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkTaskPoolService;
import com.ruicar.afs.cloud.afscase.autoaudit.loan.StepParam;
import com.ruicar.afs.cloud.afscase.autoaudit.util.ActiveStepUtil;
import com.ruicar.afs.cloud.afscase.channel.service.ChannelBaseInfoService;
import com.ruicar.afs.cloud.afscase.channel.service.ChannelQuotaInfoService;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseBaseInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseChannelInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseContractInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseCustInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseBaseInfoService;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseChannelInfoService;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseContractInfoService;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseCustInfoService;
import com.ruicar.afs.cloud.afscase.loanactivatepool.condition.LoanActivateCondition;
import com.ruicar.afs.cloud.afscase.loanactivatepool.entity.LoanActivatePool;
import com.ruicar.afs.cloud.afscase.loanactivatepool.mapper.LoanActivatePoolMapper;
import com.ruicar.afs.cloud.afscase.loanactivatepool.service.IContractActiveProcess;
import com.ruicar.afs.cloud.afscase.loanactivatepool.service.LoanActivateService;
import com.ruicar.afs.cloud.afscase.loanactivatepool.vo.LoanActivatePoolVO;
import com.ruicar.afs.cloud.afscase.loanapprove.condition.LoanApproveCondition;
import com.ruicar.afs.cloud.afscase.loanapprove.service.LoanWorkflowService;
import com.ruicar.afs.cloud.afscase.mq.approvesendinfo.service.ApproveLoanInfoService;
import com.ruicar.afs.cloud.afscase.paramconfmanagement.entity.CaseConfParam;
import com.ruicar.afs.cloud.afscase.paramconfmanagement.service.CaseConfParamService;
import com.ruicar.afs.cloud.afscase.processor.enums.LoanSubmitEnum;
import com.ruicar.afs.cloud.afscase.risk.service.CaseTortoiseService;
import com.ruicar.afs.cloud.bizcommon.business.service.ApplyCostDetailsService;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.security.service.AfsUser;
import com.ruicar.afs.cloud.common.core.security.util.SecurityUtils;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.*;
import com.ruicar.afs.cloud.common.modules.dto.mq.loan.LoanDiscardDTO;
import com.ruicar.afs.cloud.risk.api.enums.tortoise.GwtTortoiseAntiFraudCallStep;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @author yk.Li
 * @description 放款待激活池实现类
 * @date 2020/5/16 17:24
 */
@Service
@AllArgsConstructor
@Data
@Slf4j
public class LoanActivateServiceImpl  extends ServiceImpl<LoanActivatePoolMapper,LoanActivatePool> implements LoanActivateService {

    private CaseContractInfoService caseContractInfoService;
    private CaseCustInfoService caseCustInfoService;
    private CaseChannelInfoService caseChannelInfoService;
    private final CaseConfParamService caseConfParamService;
    private WorkTaskPoolService workTaskPoolService;
    private WorkProcessScheduleInfoService workProcessScheduleInfoService;
    /**
     * MQservice
     */
    private final ApproveLoanInfoService approveLoanInfoService;

    /**
     * 工作流
     */
    private final LoanWorkflowService loanWorkflowService;

    private ApplyCostDetailsService applyCostDetailsService;

    private ChannelQuotaInfoService channelQuotaInfoService;

    private ChannelBaseInfoService channelBaseInfoService;

    private CaseBaseInfoService caseBaseInfoService;

    private IContractActiveProcess contractActiveProcess;

    private CaseTortoiseService caseTortoiseService;

    private CaseApproveRecordService caseApproveRecordService;

    /**
     * 激活  推送信息到合同系统
     *
     * @param id
     */
    @Transactional
    @Override
    public void doActivate(Long id) {
        LoanActivatePool info = this.getById(id);
        if (null != info) {
            log.info("{}合同激活开始执行",info.getContractNo());
            StepParam stepParams=new StepParam();
            stepParams.setContractNo(info.getContractNo());
            ActiveStepUtil.prevSteps(stepParams);
        }
    }

    @Override
    public void loanActivateAutoAudit() {
        CaseConfParam confParam = caseConfParamService
                .getOne(Wrappers.<CaseConfParam>query().lambda().eq(CaseConfParam::getParamType, "CONTRACT_AUTO_ACTIVE"));
        boolean flag = confParam.getParamValue().equals(WhetherEnum.YES.getCode())&&confParam.getParamStatus().equals(WhetherEnum.YES.getCode());
        if (flag) {
            log.info("自动激活合同开始");
            List<LoanActivatePool> list= this.list(Wrappers.<LoanActivatePool>lambdaQuery()
                    .eq(LoanActivatePool::getActStatus, ActivateStatusEnum.UN_ACTIVATE.getStatus()));
            if (CollectionUtil.isEmpty(list)) {
                return;
            }
            for (LoanActivatePool pool : list) {
                try {
                    log.info("{}合同自动激活--start", pool.getContractNo());
                    doActivate(pool.getId());
                    log.info("{}合同自动激活完成", pool.getContractNo());
                } catch (Exception e) {
                    log.error("{}合同激活失败:{}", pool.getContractNo(), e.getMessage());
                }
            }
        } else {
            log.info("自动激活合同关闭");
        }
    }

    @Transactional
    @Override
    public void updateDiscardData(Long[] ids) {
        for (Long id : ids) {
            LoanActivatePool pool = this.getById(id);
            if (null != pool && null != pool.getContractActivateFlag()) {
                //如果收到合同激活落库通知则不提交流程
                throw new AfsBaseException("已激活数据不可执行废弃操作...");
            }
            pool.setLoanApproveStatus(ApplyStatusEnum.LOAN_DISCARD.getState());
            pool.setActStatus(ActivateStatusEnum.DISCARD.getStatus());
            this.updateById(pool);

            try{
                //修改合同状态
                caseContractInfoService.update(Wrappers.<CaseContractInfo>lambdaUpdate()
                        .eq(CaseContractInfo::getContractNo,pool.getContractNo())
                        .set(CaseContractInfo::getApplyStatus, ApplyStatusEnum.LOAN_DISCARD.getState())
                        .set(CaseContractInfo::getBusinessStage,BusinessStageEnum.LOAN_DISCARD.getCode())
                        .set(CaseContractInfo::getContractStatus, ContractStatusEnum.contractCancel));
                //记录合同取消日志
                List<WorkTaskPool> pools = workTaskPoolService.list(Wrappers.<WorkTaskPool>query().lambda()
                        .eq(WorkTaskPool::getContractNo,pool.getContractNo()));
                CaseApproveRecord lockOprRecord = new CaseApproveRecord();
                lockOprRecord.setContractNo(pool.getContractNo());
                lockOprRecord.setUseScene(UseSceneEnum.GENERAL_LOAN.getValue());
                lockOprRecord.setApproveSuggest(ApplyStatusEnum.LOAN_DISCARD.getState());
                lockOprRecord.setApproveSuggestName("合同取消");
                lockOprRecord.setApproveStartTime(new Date());
                lockOprRecord.setApproveEndTime(new Date());
                lockOprRecord.setDisposeNode(pools.get(0).getTaskNodeId());
                lockOprRecord.setDisposeNodeName(pools.get(0).getTaskNodeName());
                lockOprRecord.setDisposeStaff(SecurityUtils.getUser().getUserRealName());
                lockOprRecord.setApproveType(ApproveTypeEnum.CANAEL.getValue());
                lockOprRecord.setStageId(pools.get(0).getStageId());
                caseApproveRecordService.save(lockOprRecord);
                //废弃信息通知进件系统
                approveLoanInfoService.sendToApplyNotic(pool.getContractNo(),ApplyStatusEnum.LOAN_DISCARD);
                //结束工作流
                loanWorkflowService.giveUpWorkflow(pool.getContractNo(), LoanProcessTypeEnum.GENERAL_LOAN.getCode());
                // 放款流程结束触发玄武反欺诈
                caseTortoiseService.safeSignalFraudHand(pool.getApplyNo(), GwtTortoiseAntiFraudCallStep.AFTER_LOAN_APPLY_END);
            }catch (Exception e){
                log.info("执行废弃操作失败！",e);
            }
        }
    }

    @Transactional
    @Override
    public void discardCase(LoanDiscardDTO loanDiscardDTO) {
            try {
                CaseContractInfo caseContractInfo = caseContractInfoService.getOne(Wrappers.<CaseContractInfo>query().lambda()
                        .eq(CaseContractInfo::getContractNo,loanDiscardDTO.getContractNo()));
                if(!ObjectUtils.isEmpty(caseContractInfo)){
                    //修改合同状态
                    caseContractInfo.setBusinessStage(BusinessStageEnum.LOAN_DISCARD.getCode());
                    caseContractInfo.setApplyStatus(ApplyStatusEnum.LOAN_DISCARD.getState());
                    caseContractInfo.setContractStatus(ContractStatusEnum.contractCancel);
                    caseContractInfoService.updateById(caseContractInfo);
                    //记录合同取消日志
                    List<WorkTaskPool> pool = workTaskPoolService.list(Wrappers.<WorkTaskPool>query().lambda()
                            .eq(WorkTaskPool::getContractNo,loanDiscardDTO.getContractNo()));
                    String disposeStaff ="";
                    CaseApproveRecord lockOprRecord = new CaseApproveRecord();
                    lockOprRecord.setContractNo(loanDiscardDTO.getContractNo());
                    lockOprRecord.setUseScene(UseSceneEnum.GENERAL_LOAN.getValue());
                    AfsUser user=SecurityUtils.getUser();
                    if(com.baomidou.mybatisplus.core.toolkit.ObjectUtils.isNotEmpty(user)){
                        disposeStaff=user.getUserRealName();
                    } else {
                        disposeStaff="合作商";
                    }
                    lockOprRecord.setDisposeStaff(disposeStaff);
                    lockOprRecord.setApproveSuggest(ApplyStatusEnum.LOAN_DISCARD.getState());
                    lockOprRecord.setApproveSuggestName("合同取消");
                    lockOprRecord.setApproveStartTime(new Date());
                    lockOprRecord.setApproveEndTime(new Date());
                    lockOprRecord.setDisposeNode(pool.get(0).getTaskNodeId());
                    lockOprRecord.setDisposeNodeName(pool.get(0).getTaskNodeName());
                    lockOprRecord.setApproveType(ApproveTypeEnum.CANAEL.getValue());
                    lockOprRecord.setStageId(pool.get(0).getStageId());
                    lockOprRecord.setFlowNode(caseContractInfo.getFlowNode());
                    caseApproveRecordService.save(lockOprRecord);
                    //结束工作流
                    loanWorkflowService.giveUpWorkflow(loanDiscardDTO.getContractNo(), LoanProcessTypeEnum.GENERAL_LOAN.getCode());
                    // 放款流程结束触发玄武反欺诈
                    caseTortoiseService.safeSignalFraudHand(caseContractInfo.getApplyNo(), GwtTortoiseAntiFraudCallStep.AFTER_LOAN_APPLY_END);
                } else {
                    CaseBaseInfo caseBaseInfo = caseBaseInfoService.getOne(Wrappers.<CaseBaseInfo>query().lambda()
                            .eq(CaseBaseInfo::getApplyNo,loanDiscardDTO.getApplyNo()));
                    if(!ObjectUtils.isEmpty(caseBaseInfo)){
                        caseBaseInfo.setBusinessStateIn(AfsEnumUtil.key(BusinessStateInEnum.CANCEL));
                        caseBaseInfoService.updateById(caseBaseInfo);
                    }
                }
            }catch (Exception e){
                log.info("{}合同废弃失败！",loanDiscardDTO.getContractNo(),e);
            }
    }

    /**
     * @param contractNo
     * @param status
     * @Description 合作商撤回合同操作
     * @Author rongji.zhang
     * @Date 2020/08/31
     */
    @Override
    public void backCase(String contractNo, String status) {
        CaseContractInfo caseContractInfo = caseContractInfoService.getOne(Wrappers.<CaseContractInfo>query().lambda()
                .eq(CaseContractInfo::getContractNo, contractNo));
        if (null != caseContractInfo) {
            if(!caseContractInfo.getApplyStatus().equals(ApplyStatusEnum.LOAN_QUEUE.getState()) && !caseContractInfo.getApplyStatus().equals(ApplyStatusEnum.WAIT_ASSIGN.getState())){
                //如果收到合同激活落库通知则不提交流程
                throw new AfsBaseException("已发起流程案件数据不可执行撤回操作...");
            }
            try{
                //删除工作流程
                List<WorkProcessScheduleInfo> workProcessScheduleInfoList = workProcessScheduleInfoService.list(Wrappers.<WorkProcessScheduleInfo>query().lambda()
                        .eq(WorkProcessScheduleInfo::getContractNo,contractNo));
                workProcessScheduleInfoList.forEach(workProcessScheduleInfo -> {
                    workProcessScheduleInfoService.removeById(workProcessScheduleInfo);
                });
                //修改合同状态
                caseContractInfo.setApplyStatus(ApplyStatusEnum.LOAN_WAIT_SUBMIT.getState());
                caseContractInfo.setWorkflowPrevStep(0);
                caseContractInfoService.updateById(caseContractInfo);
                //结束工作流
                loanWorkflowService.giveUpWorkflow(contractNo, LoanProcessTypeEnum.GENERAL_LOAN.getCode());
            }catch (Exception e){
                log.info("执行撤回操作失败！",e);
            }
        } else {
            log.info("未找到需要撤回的合同！");
        }
    }


    @Transactional
    @Override
    public void doActivateOfArtificial(Long[] ids) {
        for (Long id : ids) {
            this.doActivate(id);
        }
    }

    @Transactional
    @Override
    public void submitBackLoan(Long id) {
        LoanActivatePool info = this.getById(id);
        //如果收到合同通知 则不允许退回放款
        Assert.isTrue(StringUtils.isBlank(info.getContractActivateFlag()),"已激活数据不可执行退回...");

        //修改放款审核状态
        CaseContractInfo caseContractInfo=caseContractInfoService.getOne(Wrappers.<CaseContractInfo>lambdaQuery().eq(CaseContractInfo::getContractNo,info.getContractNo()));
        caseContractInfo.setApplyStatus(ApplyStatusEnum.LOAN_WAIT_CONFIRM.getState());
        caseContractInfo.setFlowNode(FlowNodeEnum.REVIEW.getCode());
        caseContractInfoService.updateById(caseContractInfo);
        log.info("*****************" + info.getContractNo() + " 放款审核状态change:" + ApplyStatusEnum.LOAN_WAIT_CONFIRM.getState() + "*****************");
        //删除历史激活池数据
        caseContractInfoService.removeById(info);
        //工作流提交流程  保存操作记录
        LoanApproveCondition condition = new LoanApproveCondition();
        condition.setAutoFlag(Boolean.TRUE);
        condition.setContractNo(info.getContractNo());
        condition.setApplyNo(info.getApplyNo());
        condition.setApproveType(ApproveTypeEnum.PROCESS.getValue());
        condition.setUseScene(UseSceneEnum.GENERAL_LOAN.getValue());
        condition.setApproveSuggest(AfsEnumUtil.key(LoanSubmitEnum.BACK));
        condition.setFlowNode(FlowNodeEnum.AUTO.getCode());
        loanWorkflowService.submitWorkflowByScheduleInfo(condition);
    }

    /**
     * @param
     * @description 结束工作流
     * @author yk.Li
     * @date 2020/7/31
     */
    public void submitWorkflow(Long id) {
        LoanActivatePool info = this.getById(id);
        if (null != info) {
            LoanApproveCondition condition = new LoanApproveCondition();
            condition.setAutoFlag(Boolean.TRUE);
            condition.setContractNo(info.getContractNo());
            condition.setApplyNo(info.getApplyNo());
            condition.setApproveType(ApproveTypeEnum.PROCESS.getValue());
            condition.setUseScene(UseSceneEnum.GENERAL_LOAN.getValue());
            condition.setApproveSuggest(AfsEnumUtil.key(LoanSubmitEnum.SUBMIT));
            condition.setFlowNode(FlowNodeEnum.AUTO.getCode());
            //工作流流程结束  保存操作记录
            WorkTaskPool pool = workTaskPoolService.getOne(Wrappers.<WorkTaskPool>lambdaQuery()
                    .eq(WorkTaskPool::getContractNo, info.getContractNo())
                    .eq( WorkTaskPool::getProcessType, condition.getUseScene()), false);
            if(!ObjectUtils.isEmpty(pool)) {
                loanWorkflowService.submitWorkflowByScheduleInfo(condition);
            }
        }
    }

    @Transactional
    public void doLoanActivate(LoanActivatePool pool) {
        //设为已激活状态
        pool.setActStatus(ActivateStatusEnum.ACTIVATE.getStatus());
        pool.setActTime(new Date());
        this.updateById(pool);
        //通过MQ推送信息到合同系统
        approveLoanInfoService.sendLoanMsgToContract(pool.getContractNo());
    }

    /**
     * 只有GPS审核状态、额度审核状态都通过后，才自动会激活合同
     *
     * @param pool
     * @return
     */
    public boolean canActivateContract(LoanActivatePool pool) {
        Boolean canActivate = Boolean.FALSE;
        if (WhetherEnum.YES.getCode().equals(pool.getGpsApproveStatus())
                && WhetherEnum.YES.getCode().equals(pool.getLimitApproveStatus())) {
            canActivate = Boolean.TRUE;
        }
        return canActivate;
    }

    /**
     * 批量更新放款激活状态
     *
     * @param id
     */
    @Override
    public Boolean updateActStatusById(Long id, String state) {
        LoanActivatePool pool = this.getById(id);
        if (null != pool) {
            //如果审核状态有一项不通过
            Assert.isTrue(canActivateContract(pool), "【GPS审核/额度审核】未通过，推送数据失败");
            //设为已激活状态
            pool.setActStatus(state);
            pool.setActTime(new Date());
            //放款审核通过
            pool.setLoanApproveStatus(ApplyStatusEnum.LOAN_APPROVE_DONE.getState());
            pool.setLoanApproveTime(new Date());
            this.updateById(pool);
        }
        return Boolean.TRUE;
    }

    /**
     * 联表查询待放款池数据
     *
     * @param page
     * @param loanActivateCondition
     * @return
     */
    @Override
    public IPage<LoanActivatePoolVO> getLoanActivateInfoList(Page page, LoanActivateCondition loanActivateCondition) {
        return baseMapper.getLoanActivateInfoList(page, loanActivateCondition);
    }

    /**
     * 联表查询待放款池数据
     *
     * @param
     * @return
     */
    @Override
    public List<LoanActivatePoolVO> getLoanActivateInfoLists() {
        return baseMapper.getLoanActivateInfoLists();
    }

    @Override
    public void addLoanActivateInfo(String applyNo) {
        CaseContractInfo caseContractInfo = caseContractInfoService.getOne(Wrappers.<CaseContractInfo>lambdaQuery()
                .eq(StringUtils.isNotEmpty(applyNo), CaseContractInfo::getApplyNo, applyNo), false);
        CaseCustInfo caseCustInfo = caseCustInfoService.getOne(Wrappers.<CaseCustInfo>query().lambda()
                .eq(StringUtils.isNotEmpty(applyNo), CaseCustInfo::getApplyNo, applyNo)
                .eq(CaseCustInfo::getCustRole, CustRoleEnum.MIANCUST.getCode()), false);
        CaseChannelInfo caseChannelInfo = caseChannelInfoService.getOne(Wrappers.<CaseChannelInfo>query().lambda()
                .eq(StringUtils.isNotEmpty(applyNo), CaseChannelInfo::getApplyNo, applyNo));

        //待激活池插入数据
        LoanActivatePool loanActivatePool = this.getOne(Wrappers.<LoanActivatePool>lambdaQuery()
                .eq(StringUtils.isNotEmpty(applyNo), LoanActivatePool::getApplyNo, applyNo));
        if (null == loanActivatePool) {
            loanActivatePool = new LoanActivatePool();
        }
        loanActivatePool.setApplyNo(applyNo);
        loanActivatePool.setContractNo(null != caseContractInfo ? caseContractInfo.getContractNo() : "");
        loanActivatePool.setCustId(null != caseCustInfo ? caseCustInfo.getId().toString() : "");
        loanActivatePool.setDealerNo(null != caseChannelInfo ? caseChannelInfo.getDealerNo() : "");
        loanActivatePool.setActStatus(ActivateStatusEnum.UN_ACTIVATE.getStatus());
        loanActivatePool.setGpsApproveStatus(WhetherEnum.YES.getCode());
        loanActivatePool.setLimitApproveStatus(WhetherEnum.NO.getCode());
        loanActivatePool.setLoanApproveStatus(ApplyStatusEnum.LOAN_PRE_APPROVE.getState());
        this.saveOrUpdate(loanActivatePool);
    }
}
